import re
import logging
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import openai
import json
from datetime import datetime

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class NLPUtils:
    """NLP工具函数集"""
    
    def __init__(self, config):
        self.config = config
        openai.api_key = self.config["openai_api_key"]
        openai.base_url = self.config.get("openai_base_url", "https://api.openai.com/v1/")
        
    def calculate_text_similarity(self, text1, text2, method='tfidf'):
        """计算文本相似度
        
        Args:
            text1 (str): 第一段文本
            text2 (str): 第二段文本
            method (str): 相似度计算方法，'tfidf'或'embedding'
            
        Returns:
            float: 相似度得分(0-1)
        """
        if not text1 or not text2:
            return 0.0
            
        if method == 'tfidf':
            return self._tfidf_similarity(text1, text2)
        elif method == 'embedding':
            return self._embedding_similarity(text1, text2)
        else:
            logger.warning(f"未知的相似度计算方法: {method}，使用tfidf")
            return self._tfidf_similarity(text1, text2)
    
    def _tfidf_similarity(self, text1, text2):
        """基于TF-IDF的相似度计算"""
        try:
            vectorizer = TfidfVectorizer()
            tfidf_matrix = vectorizer.fit_transform([text1, text2])
            
            # 计算余弦相似度
            cos_sim = cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[1:2])
            return float(cos_sim[0][0])
        except Exception as e:
            logger.error(f"TF-IDF相似度计算错误: {str(e)}")
            return 0.0
    
    def _embedding_similarity(self, text1, text2):
        """基于词嵌入的相似度计算"""
        try:
            # 获取OpenAI嵌入
            response1 = openai.embeddings.create(
                model=self.config["embedding_model"],
                input=text1
            )
            embedding1 = response1.data[0].embedding
            
            response2 = openai.embeddings.create(
                model=self.config["embedding_model"],
                input=text2
            )
            embedding2 = response2.data[0].embedding
            
            # 计算余弦相似度
            similarity = self._cosine_similarity_vectors(embedding1, embedding2)
            return similarity
        except Exception as e:
            logger.error(f"嵌入相似度计算错误: {str(e)}")
            return 0.0
    
    def _cosine_similarity_vectors(self, v1, v2):
        """计算两个向量的余弦相似度"""
        v1 = np.array(v1)
        v2 = np.array(v2)
        
        dot_product = np.dot(v1, v2)
        norm_v1 = np.linalg.norm(v1)
        norm_v2 = np.linalg.norm(v2)
        
        if norm_v1 == 0 or norm_v2 == 0:
            return 0.0
            
        return dot_product / (norm_v1 * norm_v2)
    
    def extract_keywords(self, text, num_keywords=10):
        """提取文本关键词
        
        Args:
            text (str): 输入文本
            num_keywords (int): 提取关键词数量
            
        Returns:
            list: 关键词列表
        """
        try:
            # 使用LLM提取关键词
            response = openai.chat.completions.create(
                model=self.config["llm_model"],
                messages=[
                    {"role": "system", "content": "你是一名文本分析专家，请从文本中提取最重要的关键词。"},
                    {"role": "user", "content": f"请从以下文本中提取{num_keywords}个最重要的关键词，以JSON数组格式返回:\n\n{text}"}
                ],
                temperature=0.3,
                response_format={"type": "json_object"}
            )
            
            result = json.loads(response.choices[0].message.content)
            
            if "keywords" in result:
                return result["keywords"]
            return []
            
        except Exception as e:
            logger.error(f"关键词提取错误: {str(e)}")
            
            # 简单备选方案：基于词频
            return self._extract_keywords_by_frequency(text, num_keywords)
    
    def _extract_keywords_by_frequency(self, text, num_keywords=10):
        """基于词频提取关键词（简单备选方案）"""
        # 简单分词
        words = re.findall(r'\b\w+\b', text.lower())
        
        # 去除停用词（简化版）
        stop_words = {'的', '了', '是', '在', '我', '有', '和', '就', '不', '人', '都', '一', '一个', '上', '也', '很', '到', '说', '要', '去', '你', '会', '着', '没有', '看', '好', '自己', '这'}
        filtered_words = [word for word in words if word not in stop_words and len(word) > 1]
        
        # 计算词频
        word_freq = {}
        for word in filtered_words:
            if word in word_freq:
                word_freq[word] += 1
            else:
                word_freq[word] = 1
                
        # 按频率排序
        sorted_words = sorted(word_freq.items(), key=lambda x: x[1], reverse=True)
        
        # 返回前N个关键词
        return [word for word, freq in sorted_words[:num_keywords]]
    
    def summarize_text(self, text, max_length=200):
        """文本摘要生成
        
        Args:
            text (str): 输入文本
            max_length (int): 摘要最大长度
            
        Returns:
            str: 生成的摘要
        """
        try:
            # 使用LLM生成摘要
            response = openai.chat.completions.create(
                model=self.config["llm_model"],
                messages=[
                    {"role": "system", "content": "你是一位文本摘要专家，请生成准确简洁的摘要。"},
                    {"role": "user", "content": f"请为以下文本生成一个不超过{max_length}字的简洁摘要:\n\n{text}"}
                ],
                temperature=0.5,
                max_tokens=max_length
            )
            
            return response.choices[0].message.content.strip()
            
        except Exception as e:
            logger.error(f"摘要生成错误: {str(e)}")
            
            # 简单摘要：取前N个字符
            if len(text) <= max_length:
                return text
            return text[:max_length] + "..."
    
    def classify_text(self, text, categories):
        """文本分类
        
        Args:
            text (str): 输入文本
            categories (list): 分类类别列表
            
        Returns:
            dict: 各类别概率
        """
        try:
            # 将类别转换为字符串
            categories_str = ", ".join(categories)
            
            # 使用LLM进行分类
            response = openai.chat.completions.create(
                model=self.config["llm_model"],
                messages=[
                    {"role": "system", "content": "你是一位文本分类专家，请准确判断文本所属类别。"},
                    {"role": "user", "content": f"请将以下文本分类到这些类别中: {categories_str}。返回一个JSON对象，包含每个类别的概率(0-1):\n\n{text}"}
                ],
                temperature=0.3,
                response_format={"type": "json_object"}
            )
            
            result = json.loads(response.choices[0].message.content)
            
            # 确保所有类别都有值
            for category in categories:
                if category not in result:
                    result[category] = 0.0
                    
            return result
            
        except Exception as e:
            logger.error(f"文本分类错误: {str(e)}")
            
            # 简单备选方案：基于关键词匹配
            return self._classify_by_keywords(text, categories)
    
    def _classify_by_keywords(self, text, categories):
        """基于关键词的简单分类（备选方案）"""
        text = text.lower()
        result = {}
        
        for category in categories:
            # 简单匹配：类别词在文本中出现的次数
            category_lower = category.lower()
            count = text.count(category_lower)
            
            # 设置一个基础分数
            if count > 0:
                result[category] = min(0.8, 0.2 + count * 0.2)  # 最高0.8
            else:
                result[category] = 0.1
                
        # 标准化概率和为1
        total = sum(result.values())
        if total > 0:
            for category in result:
                result[category] /= total
                
        return result
    
    def parse_date_expressions(self, text):
        """解析文本中的日期表达式
        
        Args:
            text (str): 输入文本
            
        Returns:
            list: 解析出的日期表达式
        """
        # 简单的日期正则表达式
        date_patterns = [
            r'\d{4}[-/年]\d{1,2}[-/月]\d{1,2}[日号]?',  # 2023-01-01, 2023年01月01日
            r'\d{1,2}[-/月]\d{1,2}[日号]?',            # 01-01, 1月1日
            r'今天|明天|后天|昨天|前天',                # 相对日期
            r'下周[一二三四五六日天]|本周[一二三四五六日天]',  # 工作日
            r'上个月|这个月|下个月',                    # 月份
            r'\d{1,2}天[后前]',                       # X天后/前
            r'\d{1,2}个月[后前]',                     # X个月后/前
        ]
        
        found_dates = []
        for pattern in date_patterns:
            matches = re.findall(pattern, text)
            found_dates.extend(matches)
            
        return found_dates
    
    def extract_sentiment(self, text):
        """提取文本情感倾向
        
        Args:
            text (str): 输入文本
            
        Returns:
            dict: 情感分析结果
        """
        try:
            # 使用LLM分析情感
            response = openai.chat.completions.create(
                model=self.config["llm_model"],
                messages=[
                    {"role": "system", "content": "你是一位情感分析专家，请分析文本的情感倾向。"},
                    {"role": "user", "content": f"请分析以下文本的情感倾向，返回一个JSON对象，包含积极、消极和中性三种情感的概率值(0-1)，以及情感值(-1到1，-1为极度消极，1为极度积极):\n\n{text}"}
                ],
                temperature=0.3,
                response_format={"type": "json_object"}
            )
            
            result = json.loads(response.choices[0].message.content)
            return result
            
        except Exception as e:
            logger.error(f"情感分析错误: {str(e)}")
            
            # 简单备选方案
            return {
                "positive": 0.33,
                "negative": 0.33,
                "neutral": 0.34,
                "sentiment_value": 0.0
            } 